use std::collections::HashMap;
use std::path::Path;
use std::str::FromStr;

use plotlib::page::Page;
use plotlib::repr::Plot;
use plotlib::style::{LineJoin, LineStyle};
use plotlib::view::ContinuousView;

pub enum Drawer {
    MulPage,
    OnePage,
}

impl FromStr for Drawer {
    type Err = ();
    fn from_str(src: &str) -> Result<Self, ()> {
        return match src {
            "mul_page" => Ok(Drawer::MulPage),
            "one_page" => Ok(Drawer::OnePage),
            _ => Err(()),
        };
    }
}

impl Default for Drawer {
    fn default() -> Self {
        Self::OnePage
    }
}

impl Drawer {
    pub fn draw_results<P: AsRef<Path>>(&self, 
        results: &HashMap<String, Vec<f64>>, 
        sim_time: f64, delta_time: f64,
        output_path: P
    ) -> Result<(), String>
    {
        match self {
            Self::MulPage => draw_results_mulpage(results, sim_time, delta_time, output_path),
            Self::OnePage => draw_results_onepage(results, sim_time, delta_time, output_path),
        }
    }
}

fn draw_results_mulpage<P: AsRef<Path>>(
    results: &HashMap<String, Vec<f64>>, 
    _sim_time: f64, delta_time: f64,
    output_path: P
) -> Result<(), String> 
{
    for (name, result) in results {
        let data = result.iter()
            .enumerate()
            .map(|(i, v)| (i as f64 * delta_time, *v))
            .collect();

        let l1 = Plot::new(data).line_style(LineStyle::new()
            .colour("burlywood")
            .linejoin(LineJoin::Round),
        );

        let v = ContinuousView::new()
            .add(l1)
            .x_label("time")
            .y_label("value");

        Page::single(&v)
            .save(output_path.as_ref().join(format!("{}.svg", name)))
            .map_err(|err| format!("Save svg: {:?}", err))?
    }

    Ok(())
}

fn draw_results_onepage<P: AsRef<Path>>(
    results: &HashMap<String, Vec<f64>>, 
    _sim_time: f64, delta_time: f64,
    output_path: P
) -> Result<(), String> 
{
    let colors = [
        "red", "blue", "green", "yellow", "cyan", "magenta", "darkgray", "purple"
    ].into_iter().cycle();

    let lines = results.iter()
        .zip(colors)
        .map(|((name, result), color)| {
            let data = result.iter()
                .enumerate()
                .map(|(i, v)| (i as f64 * delta_time, *v))
                .collect();

            let line = Plot::new(data)
                .line_style(LineStyle::new()
                    .colour(color)
                    .linejoin(LineJoin::Round),
                )
                .legend(name.to_string());

            line
        });

    let mut v = ContinuousView::new()
        .x_label("time")
        .y_label("value");

    for line in lines {
        v = v.add(line);
    }

    Page::single(&v)
        .save(output_path.as_ref().join("result.svg"))
        .map_err(|err| format!("Save svg: {:?}", err))
}
